package com.ulife.order.service.domain;

import com.alibaba.dubbo.common.json.JSON;
import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.config.annotation.Reference;
import com.sun.jdi.DoubleValue;
import com.ulife.base.entities.order.*;
import com.ulife.base.logics.order.*;
import com.ulife.common.gateway.utils.define.Version;
import com.ulife.common.gateway.utils.entity.ServiceException;
import com.ulife.common.utils.lang.JsonMapper;
import com.ulife.member.api.MemberService;
import com.ulife.order.api.OrderService;
import com.ulife.order.api.errors.OrderErrorCodes;
import com.ulife.order.service.componentConst.*;
import com.ulife.order.service.dto.*;
import com.ulife.order.service.enumeration.SaleOrderPayStatus;
import com.ulife.order.service.enumeration.SaleOrderStatus;
import com.ulife.order.service.enumeration.PayStatus;
import com.ulife.order.service.util.HttpUtil;
import com.ulife.order.service.util.JsonUtils;
import com.ulife.product.api.ProductService;
import com.ulife.product.api.resposne.productInfo.ProductMoreResponse;
import com.ulife.product.api.resposne.productInfo.SubProductMoreDTO;
import org.dozer.DozerBeanMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by Ulife on 2016/1/18.
 */
@Service
public class Schedule {
    private static Lock cancelLock = new ReentrantLock();
    private static Lock splitLock = new ReentrantLock();
    private static Lock syncLock = new ReentrantLock();
    private static Lock pushLock = new ReentrantLock();

    Logger logger = LoggerFactory.getLogger(com.ulife.order.service.domain.Order.class);

    private final String COD_NAME = "货到付款";
    private final String PAY_CHANNEL_BALANCE = "balance";


    @Resource
    SaleOrderLogic saleOrderLogic;

    @Resource
    com.ulife.order.service.domain.Order orderDomain;

    @Resource
    SaleOrderItemLogic saleOrderItemLogic;

    @Value("${order.cancel.timeout}")
    int orderCancelTimeout;

    @Value("${order.stop.time}")
    String orderStopTime;

    @Value("${order.stop.time.cm}")
    String orderStopTimeCM;

    @Value("${order.cancel.permit.default}")
    String orderCancelPermit;

    @Value("${order.cancel.permit.limit}")
    String orderCancelPermitLimit;

    @Value("${order.schedule.appId}")
    String appId;

    @Value("${order.schedule.signKey}")
    String signKey;

    @Value("${order.push.mainUrl}")
    String mainUrl;

    @Value("${order.push.subUrl}")
    String subUrl;

    @Value("${order.sync.url}")
    String syncUrl;

    @Resource
    DozerBeanMapper dozerBeanMapper;

    @Resource
    SaleOrderItemPromotionLogic saleOrderItemPromotionLogic;

    @Resource
    SaleOrderShipLogic saleOrderShipLogic;

    @Resource
    SaleOrderPayLogic saleOrderPayLogic;

    @Resource
    SyncTimeLogic syncTimeLogic;

    @Resource
    SaleOrderStatusLogLogic saleOrderStatusLogLogic;

    @Resource
    SaleOrderTrackingLogic saleOrderTrackingLogic;

    @Resource
    ShipmentOrderItemLogic shipmentOrderItemLogic;

    @Reference(version = Version.LATEST)
    MemberService memberService;

    @Reference(version = Version.LATEST)
    ProductService productService;

    @Reference(version = Version.LATEST)
    OrderService orderService;

    private static JsonMapper Json = JsonMapper.nonDefaultMapper();
    /*
    * 请求签名
    * */
    private String sign(String appId, long timestamp, String signKey) {
        String rtn = null;
        String signature = (String.valueOf(timestamp)).concat(signKey);
        rtn = com.ulife.order.service.util.DESUtils.getMD5Str(signature.toString());
        return rtn;
    }

    //region 从om同步订单状态&物流信息到新后台
    /*
    * 从om同步订单状态&物流信息到新后台
    * */
    public String sync() {
        logger.info("start sync method");

        String rtn = null;
        syncLock.lock();
        try {
            //get last sync time
            SyncTime syncTime = syncTimeLogic.get(1L);
            if (syncTime == null) return rtn;
            Date last = syncTime.getSaleOrderTrackingSync();
            Date now = Calendar.getInstance().getTime();
            Date next = Calendar.getInstance().getTime();
            Date temp = new Date(last.getTime() + 1000 * 60 * 60 * 2);//最多2h间隔
            if (next.compareTo(temp) > 0) {
                next = temp;
            }

            //get tracking info from om
            com.ulife.order.service.dto.SyncTrackingRequest request = new com.ulife.order.service.dto.SyncTrackingRequest();
            request.StarTime = last;
            request.EndTime = next;
            request.AppId = appId;
            request.TimeStamp = now.getTime();
            request.DataSign = sign(appId, request.TimeStamp, signKey);
            String requestJsonString = null;
            try {
                requestJsonString = JSON.json(request);
            } catch (IOException e) {
                logger.error(e.getMessage(), e);
            }
            String responseJsonString = HttpUtil.httpPost(syncUrl, requestJsonString, Charset.forName("utf-8"), "application/json");
            if (responseJsonString == null || responseJsonString.isEmpty()) return rtn;

            SyncTrackingResponse response = JsonUtils.json2Obj(responseJsonString, SyncTrackingResponse.class);

            if (response == null || !response.Success) {
                return rtn;
            }

            boolean rst = true;
            try {
                rst = saveSyncInfo(response);
            } catch (Exception e) {
                logger.error(e.toString(), e);
                rst = false;
                return "fail";
            }
            if (rst) {
                //save sync_time
                syncTime.setSaleOrderTrackingSync(next);
                syncTime.setModifiedTime(Calendar.getInstance().getTime());
                syncTimeLogic.updateSelective(syncTime);
            }
        } finally {
            syncLock.unlock();
        }
        return "success";
    }

    /*
    * 保存sync信息
    * */
    @Transactional
    private boolean saveSyncInfo(SyncTrackingResponse response) throws ServiceException {

        boolean rtn = false;

        Date now = Calendar.getInstance().getTime();
        //save order status
        if (!saveOrderStatus(response.OrderstatusList)) {
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_SAVE_STATUS_ERROR);
        }
        //save tracking info and ship order info
        if (!SaveOrderTrackingAndShipOrder(response.TrackInfoList)) {
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_SAVE_SHIP_ORDER_TRACKING_ERROR);
        }
        rtn = true;
        return rtn;
    }

    /*
    * 保存订单tracking info 信息
    * */
    private boolean SaveOrderTrackingAndShipOrder(List<TrackingInfo> trackInfoList) throws ServiceException {
        boolean rtn = true;

        if (trackInfoList == null) {
            logger.warn("trackInfoList is null");
            return rtn;
        }
        for (TrackingInfo trackingInfo : trackInfoList) {
            SaveOrderTracking(trackingInfo.OrderNo, trackingInfo.Tracks);
            SaveShipOrders(trackingInfo.OrderNo, trackingInfo.ShipOrders);
        }

        return true;
    }

    /*
    * 保存订单tracking信息
    * */
    private void SaveOrderTracking(String sub_so_no, List<TrackingDetailInfo> trackingDetailInfoList) throws ServiceException {
        for (TrackingDetailInfo trackingDetailInfo : trackingDetailInfoList) {
            try {
                SaleOrderTracking sot = saleOrderTrackingLogic.get(Long.valueOf(trackingDetailInfo.Id));
                if (sot != null) continue;//已存在

                SaleOrderCriteria saleOrderCriteria = new SaleOrderCriteria();
                saleOrderCriteria.createCriteria().andSaleNoEqualTo(sub_so_no);
                List<SaleOrder> saleOrderList = saleOrderLogic.list(saleOrderCriteria);
                if (saleOrderList == null || saleOrderList.size() == 0) {
                    continue;//订单不存在
                }

                SaleOrderTracking saleOrderTracking = new SaleOrderTracking();
                saleOrderTracking.setId(Long.valueOf(trackingDetailInfo.Id));
                saleOrderTracking.setRemark(trackingDetailInfo.Remark);
                saleOrderTracking.setSoNo(saleOrderList.get(0).getPackageSaleNo());
                saleOrderTracking.setSubSaleNo(sub_so_no);
                saleOrderTracking.setShipOrderNo(trackingDetailInfo.ShipOrderNo);
                saleOrderTracking.setEvent(trackingDetailInfo.EventName);
                saleOrderTracking.setCreatedTime(trackingDetailInfo.CreatedTime);
                saleOrderTracking.setOperatorMobileNo(trackingDetailInfo.OperatorPhoneNo);
                saleOrderTracking.setOperatorName(trackingDetailInfo.OperatorName);

                saleOrderTrackingLogic.insert(saleOrderTracking);
            } catch (Exception e) {
                logger.error(e.toString(), e);
                throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_SAVE_TRACING_ERROR);
            }
        }
    }

    /*
    * 保存发货单信息
    * */
    private void SaveShipOrders(String sub_so_no, List<ShipOrderInfo> shipOrders) throws ServiceException {
        Date now = Calendar.getInstance().getTime();
        //save ship order
        for (ShipOrderInfo shipOrderInfo : shipOrders) {
            try {

                SaleOrderCriteria saleOrderCriteria = new SaleOrderCriteria();
                saleOrderCriteria.createCriteria().andSaleNoEqualTo(sub_so_no);
                List<SaleOrder> saleOrderList = saleOrderLogic.list(saleOrderCriteria);
                if (saleOrderList == null || saleOrderList.size() == 0) {
                    break;//订单不存在
                }

                //获取 items
                SaleOrderItemCriteria saleOrderItemCriteria = new SaleOrderItemCriteria();
                saleOrderItemCriteria.createCriteria().andSoNoEqualTo(sub_so_no);
                List<SaleOrderItem> saleOrderItemList = saleOrderItemLogic.list(saleOrderItemCriteria);
                if (saleOrderItemList == null || saleOrderItemList.size() == 0) {
                    break;//订单没有商品
                }

                //补齐直发订单的 ship order item
                if (shipOrderInfo.Products == null || shipOrderInfo.Products.size() == 0) {
                    shipOrderInfo.Products = new ArrayList<ShipOrderItemInfo>();
                    for (SaleOrderItem saleOrderItem : saleOrderItemList) {
                        ShipOrderItemInfo shipOrderItemInfo = new ShipOrderItemInfo();
                        shipOrderItemInfo.ProductID = saleOrderItem.getSkuId();
                        shipOrderItemInfo.Qty = saleOrderItem.getQuantity();
                    }
                }

                for (ShipOrderItemInfo info : shipOrderInfo.Products) {
                    SaleOrderItem saleOrderItem = getSaleOrderItem(info.ProductID, saleOrderItemList);
                    if (saleOrderItem == null) {//发货单商品不是订单商品
                        logger.warn("ship order item is not sale order item，sku id :".concat(info.ProductID.toString()).concat("；ShipOrderNo = ").concat(shipOrderInfo.ShipOrderNo));
                        continue;
                    }
                    ShipmentOrderItemCriteria shipmentOrderItemCriteria = new ShipmentOrderItemCriteria();
                    shipmentOrderItemCriteria.createCriteria().andShipOrderNoEqualTo(shipOrderInfo.ShipOrderNo).andSkuIdEqualTo(info.ProductID);
                    List<ShipmentOrderItem> shipmentOrderItemList = shipmentOrderItemLogic.list(shipmentOrderItemCriteria);
                    if (shipmentOrderItemList != null && shipmentOrderItemList.size() > 0) continue;//已存在

                    ShipmentOrderItem shipmentOrderItem = new ShipmentOrderItem();
                    shipmentOrderItem.setSubSoNo(sub_so_no);
                    shipmentOrderItem.setShipOrderNo(shipOrderInfo.ShipOrderNo);
                    shipmentOrderItem.setQuantity(info.Qty);
                    shipmentOrderItem.setSkuId(info.ProductID);
                    shipmentOrderItem.setCreatedTime(now);
                    shipmentOrderItem.setModifiedTime(now);
                    shipmentOrderItem.setCreatedBy("system");
                    shipmentOrderItem.setModifiedBy("system");
                    shipmentOrderItem.setItemId(saleOrderItem.getItemId());
                    shipmentOrderItem.setItemForm(saleOrderItem.getItemForm());
                    shipmentOrderItem.setSoNo(saleOrderList.get(0).getPackageSaleNo());
                    shipmentOrderItemLogic.insert(shipmentOrderItem);
                }

            } catch (Exception e) {
                logger.error(e.toString(), e);
                throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_SAVE_SHIP_ORDER_ERROR);
            }
        }
    }

    /*
    * 获取sale order item by skuId
    * */
    private SaleOrderItem getSaleOrderItem(long skuId, List<SaleOrderItem> saleOrderItemList) {
        if (skuId == 0 || saleOrderItemList == null || saleOrderItemList.size() == 0) {
            return null;
        }
        for (SaleOrderItem item : saleOrderItemList) {
            if (item.getSkuId().longValue() == skuId) return item;
        }
        return null;
    }


    /*
    * 保存订单处理状态变更
    * */
    private boolean saveOrderStatus(List<OrderStatusInfo> orderStatusList) {
        boolean rtn = true;
        Map<String, SaleOrderStatus> mainSaleOrderStatusMap = new HashMap<>();

        for (OrderStatusInfo orderStatusInfo : orderStatusList) {
            try {
                if (orderStatusInfo == null) {
                    continue;
                }
                SaleOrderCriteria saleOrderCriteria = new SaleOrderCriteria();
                saleOrderCriteria.createCriteria().andSaleNoEqualTo(orderStatusInfo.OrderNo);
                List<SaleOrder> saleOrderList = saleOrderLogic.list(saleOrderCriteria);
                if (saleOrderList == null || saleOrderList.size() == 0) {
                    continue;
                }
                SaleOrder saleOrder = saleOrderList.get(0);
                int status = getOrderStatus(orderStatusInfo.Status);//只映射SaleOrderStatus.Shipping后的状态
                if (status == 0) continue;

                if (!saveOrderStatusChangeLog(orderStatusInfo)) {//保存status change log
                    rtn = false;
                    break;
                }
                if (status == saleOrder.getStatus()) continue;

                //订单最终状态无法修改(订单取消状态可以覆盖 => for 补单)
                if (saleOrder.getStatus() != com.ulife.order.service.enumeration.SaleOrderStatus.Finished.value()
                        && saleOrder.getStatus() != com.ulife.order.service.enumeration.SaleOrderStatus.Rejected.value()) {

                    logger.info("2change sale order status from " + saleOrder.getStatus() + " to " + status);
                    saleOrder.setStatus(status);
                    saleOrder.setModifiedTime(Calendar.getInstance().getTime());
                    saleOrder.setModifiedBy("system");
                    saleOrderLogic.update(saleOrder);


                    //add status channge in sub sale order to map
                    String mainSaleOrderNo = saleOrder.getPackageSaleNo();
                    SaleOrderStatus latestSubStatus = SaleOrderStatus.valueOf(status);
                    if (!mainSaleOrderStatusMap.containsKey(mainSaleOrderNo)) {
                        mainSaleOrderStatusMap.put(mainSaleOrderNo, latestSubStatus);
                    }
                    if (mainSaleOrderStatusMap.get(mainSaleOrderNo).value() > latestSubStatus.value()) {//还有子订单是更小状态
                        mainSaleOrderStatusMap.put(mainSaleOrderNo, latestSubStatus);
                    }
                }
            } catch (Exception e) {
                logger.warn("save sub sale order status exception;" + e.getMessage());
            }
        }
        //循环main order 's sub order for update main order status
        for (String mainOrderNo : mainSaleOrderStatusMap.keySet()) {
            try {
                SaleOrderCriteria mainSaleOrderCriteria = new SaleOrderCriteria();
                mainSaleOrderCriteria.createCriteria().andSaleNoEqualTo(mainOrderNo).andIsDeleteEqualTo(0);
                List<SaleOrder> mainSaleOrderList = saleOrderLogic.list(mainSaleOrderCriteria);
                if (mainSaleOrderList == null || mainSaleOrderList.size() == 0 || mainSaleOrderList.get(0) == null)
                    continue;

                SaleOrder main = mainSaleOrderList.get(0);
                SaleOrderCriteria subSaleOrderCriteria = new SaleOrderCriteria();
                subSaleOrderCriteria.createCriteria().andPackageSaleNoEqualTo(main.getSaleNo()).andIsDeleteEqualTo(0);
                List<SaleOrder> subSaleOrderList = saleOrderLogic.list(subSaleOrderCriteria);
                if (subSaleOrderList == null || subSaleOrderList.size() == 0) continue;

                int mainStatus = main.getStatus();
                int minSubOrderStatus = subSaleOrderList.get(0).getStatus();
                for (SaleOrder subSaleOrder : subSaleOrderList) {//获取子订单最小状态
                    minSubOrderStatus = subSaleOrder.getStatus() < minSubOrderStatus ? subSaleOrder.getStatus() : minSubOrderStatus;
                }
                if (main.getStatus() != SaleOrderStatus.Finished.value() && main.getStatus() != SaleOrderStatus.Rejected.value()) {
                    logger.info("3change sale order status from " + main.getStatus() + " to " + minSubOrderStatus);

                    main.setStatus(minSubOrderStatus);
                    main.setModifiedTime(Calendar.getInstance().getTime());
                    main.setModifiedBy("system");
                    saleOrderLogic.updateSelective(main);
                }
            } catch (Exception e) {
                logger.warn("update main sale order status exception;" + e.getMessage());
            }
        }
        return rtn;
    }

    /*
    * 保存订单状态变化log
    * */
    private boolean saveOrderStatusChangeLog(com.ulife.order.service.dto.OrderStatusInfo orderStatusInfo) {
        boolean rtn = true;

        for (OrderStatusChangeInfo orderStatusChangeInfo : orderStatusInfo.StatusList) {//列表
            //todo should removed for performance?
            SaleOrderStatusLogCriteria saleOrderStatusLogCriteria = new SaleOrderStatusLogCriteria();
            saleOrderStatusLogCriteria.createCriteria().andSoNoEqualTo(orderStatusInfo.OrderNo).andFromSoStatusEqualTo(orderStatusChangeInfo.FromStatus);
            List<SaleOrderStatusLog> saleOrderStatusLogs = saleOrderStatusLogLogic.list(saleOrderStatusLogCriteria);
            if (saleOrderStatusLogs != null && saleOrderStatusLogs.size() != 0) continue;

            SaleOrderStatusLog saleOrderStatusLog = new SaleOrderStatusLog();
            saleOrderStatusLog.setSoNo(orderStatusInfo.OrderNo);
            saleOrderStatusLog.setFromSoStatus(orderStatusChangeInfo.FromStatus);
            saleOrderStatusLog.setToSoStatus(orderStatusChangeInfo.ToStatus);
            saleOrderStatusLog.setRemark(orderStatusChangeInfo.Detail);
            saleOrderStatusLog.setCreatedTime(orderStatusChangeInfo.CreatedTime);
            saleOrderStatusLog.setCreatedBy("system");

            saleOrderStatusLogLogic.insert(saleOrderStatusLog);
        }
        return rtn;
    }

    /*
    * 订单状态映射
    * */
    private int getOrderStatus(String status) {
        int rtn = 0;
        logger.info("in get order status method , parameter is " + status);
        switch (status) {
            case "已打印":
                return SaleOrderStatus.Shipping.value();
            case "等待发货":
                return SaleOrderStatus.Shipping.value();
            case "处理中":
                return SaleOrderStatus.Shipping.value();
            case "部分签收":
                return SaleOrderStatus.Shipping.value();
            case "部分发货":
                return SaleOrderStatus.Shipping.value();
            case "已发货":
                return SaleOrderStatus.Shipping.value();
            case "客户拒收":
                return SaleOrderStatus.Rejected.value();
            case "拒收关闭":
                return SaleOrderStatus.Rejected.value();
            case "暂停配送":
                return SaleOrderStatus.Suspension.value();
            case "交易成功":
                return SaleOrderStatus.Finished.value();
            case "等待取消":
                return SaleOrderStatus.Cancel.value();
            case "已取消":
                return SaleOrderStatus.Cancel.value();
        }
        logger.info("in get order status method , return is " + rtn);
        return rtn;
    }

    //endregion

    //region 推送订单到om
    /*
    * 推送订单到om系统
    * */
    public String push() {
        String rtn = null;
        logger.info("start push method");
        pushLock.lock();
        try {
            //get main sale order by status = confirmed
            SaleOrderCriteria saleOrderCriteria = new SaleOrderCriteria();
            saleOrderCriteria.createCriteria().andOrderTypeEqualTo(SaleOrderTypeConst.MAIN_SALE_ORDER).andStatusEqualTo(SaleOrderStatus.Splited.value()).andIsDeleteEqualTo(0);//推送状态为已拆单的订单
            List<SaleOrder> saleOrders = saleOrderLogic.list(saleOrderCriteria);
            if (saleOrders == null || saleOrders.size() == 0) return rtn;

            for (SaleOrder saleOrder : saleOrders) {
                //get sub sale order
                SaleOrderCriteria subSaleOrderCriteria = new SaleOrderCriteria();
                subSaleOrderCriteria.createCriteria().andPackageSaleNoEqualTo(saleOrder.getSaleNo()).andOrderTypeEqualTo(SaleOrderTypeConst.SUB_SALE_ORDER).andIsDeleteEqualTo(0);
                List<SaleOrder> subSaleOrders = saleOrderLogic.list(subSaleOrderCriteria);
                if (subSaleOrders == null || subSaleOrders.size() == 0) {
                    logger.warn("sub sale order count is 0.main sale order no = ".concat(saleOrder.getSaleNo()));
                    continue;
                }
                boolean isSuccess = true;
                try {
                    //push main order
                    isSuccess = push(saleOrder);
                    if (!isSuccess) {
                        logger.info("push main order is fale");
                        continue;
                    }
                    //push sub order
                    for (SaleOrder subSaleOrder : subSaleOrders) {
                        isSuccess = push(subSaleOrder);
                        if (!isSuccess) {
                            logger.info("push sub order is fale");
                            break;
                        }
                    }

                    if (isSuccess) {
                        updateSaleOrderStatus(saleOrder, subSaleOrders);
                    }
                } catch (ServiceException e) {
                    logger.info("订单推送异常：sale_no = ".concat(saleOrder.getSaleNo()));
                    logger.error(e.toString(), e);
                }
            }
        } finally {
            pushLock.unlock();
        }
        return rtn;
    }

    /**
     * 推送订单异常发送预警邮件通知
     * @param subject 邮件标题
     * @param content 邮件内容
     * @throws ServiceException
     */
    private  void sendOrderExceptionMail(String subject,String content)throws ServiceException{
        try {
            memberService.sendOrderWarningEmail(subject,content);
        }catch (ServiceException ex)
        {
            logger.error("【会员服务】 调用发送邮件错误,in [订单服务] 推送OM订单异常发送预警邮件.");
            logger.error(ex.toString(),ex);
        }
    }

    /*
    * 更新订单状态
    * */
    @Transactional
    private void updateSaleOrderStatus(SaleOrder mainSaleOrder, List<SaleOrder> subSaleOrders) {
        Date now = Calendar.getInstance().getTime();
        //change main sale order status
        logger.info("4change sale order status from " + mainSaleOrder.getStatus() + " to " + SaleOrderStatus.Synchronized.value());
        mainSaleOrder.setStatus(SaleOrderStatus.Synchronized.value());
        mainSaleOrder.setModifiedTime(now);
        mainSaleOrder.setModifiedBy("system");
        saleOrderLogic.update(mainSaleOrder);

        for (SaleOrder subSaleOrder : subSaleOrders) {
            logger.info("5change sale order status from " + subSaleOrder.getStatus() + " to " + SaleOrderStatus.Synchronized.value());
            subSaleOrder.setStatus(SaleOrderStatus.Synchronized.value());
            subSaleOrder.setModifiedTime(now);
            subSaleOrder.setModifiedBy("system");
            saleOrderLogic.update(subSaleOrder);
        }
    }

    /*
    * 推送订单
    * */
    private boolean push(SaleOrder saleOrder) throws ServiceException {
        boolean rtn = false;
        if (saleOrder == null) {
            logger.info("sale order is null");
            sendOrderExceptionMail("订单同步","订单数据为空.");
            return rtn;
        }

        //get sale order ship
        SaleOrderShipCriteria saleOrderShipCriteria = new SaleOrderShipCriteria();
        saleOrderShipCriteria.createCriteria().andSoNoEqualTo(saleOrder.getSaleNo());
        List<SaleOrderShip> saleOrderShipList = saleOrderShipLogic.list(saleOrderShipCriteria);
        if (saleOrderShipList == null || saleOrderShipList.size() <= 0) {
            logger.info("sale Order Ship List size is 0");
            sendOrderExceptionMail("订单同步","订单收货地址信息为空.错误订单号"+saleOrder.getSaleNo());
            return rtn;
        }

        if (saleOrder.getOrderType().equalsIgnoreCase(com.ulife.order.service.componentConst.SaleOrderTypeConst.MAIN_SALE_ORDER)) {
            logger.info("push main order start");
            rtn = pushMain(saleOrder, saleOrderShipList.get(0));
        } else {
            logger.info("push sub order start");

            //get sale order item
            SaleOrderItemCriteria saleOrderItemCriteria = new SaleOrderItemCriteria();
            saleOrderItemCriteria.createCriteria().andSoNoEqualTo(saleOrder.getSaleNo());
            List<SaleOrderItem> saleOrderItemList = saleOrderItemLogic.list(saleOrderItemCriteria);
            if (saleOrderItemList == null || saleOrderItemList.size() == 0) {
                sendOrderExceptionMail("订单同步","订单明细信息为空.错误订单号"+saleOrder.getSaleNo());
                return rtn;
            }

            //get item promotion
            SaleOrderItemPromotionCriteria saleOrderItemPromotionCriteria=new SaleOrderItemPromotionCriteria();
            saleOrderItemPromotionCriteria.createCriteria().andSoNoEqualTo(saleOrder.getSaleNo());//.andIsValidEqualTo(1);
            List<SaleOrderItemPromotion>  saleOrderItemPromotionList = saleOrderItemPromotionLogic.list(saleOrderItemPromotionCriteria);

            if (saleOrderItemPromotionList == null) {
                logger.error("getitempromotion is null.");
                saleOrderItemPromotionList = new ArrayList<>();
            }
            else
            {
                logger.error("getitempromotion:"+Json.toJson(saleOrderItemPromotionList));
            }

//            if (saleOrderItemPromotionList.size() == 0 ) {
//                logger.info("sale order item promotion list size = 0");
//                sendOrderExceptionMail("订单同步","订单有优惠,item优惠信息不能为空.错误订单号"+saleOrder.getSaleNo());
//                return rtn;//优惠订单，优惠信息不能为空
//            }

            //get pay log
            SaleOrderPayCriteria saleOrderPayCriteria = new SaleOrderPayCriteria();
            saleOrderPayCriteria.createCriteria().andSoNoEqualTo(saleOrder.getSaleNo()).andStatusEqualTo(PayStatus.Success.value());
            List<SaleOrderPay> saleOrderPayList = saleOrderPayLogic.list(saleOrderPayCriteria);

            if (saleOrderPayList == null) {
                saleOrderPayList = new ArrayList<>();
            }
            if (saleOrderPayList.size() == 0 && !saleOrder.getPayType().equalsIgnoreCase(COD_NAME)) {
                logger.info("sale order pay list size = 0");
                sendOrderExceptionMail("订单同步","订单非货到付款,支付信息不能为空.错误订单号"+saleOrder.getSaleNo());
                return rtn;//非货到付款，支付信息不能为空
            }

            rtn = pushSub(saleOrder, saleOrderItemList, saleOrderShipList.get(0), saleOrderPayList,saleOrderItemPromotionList);
        }

        return rtn;
    }

    /*
    * 推送主订单
    * */
    private boolean pushMain(SaleOrder saleOrder, SaleOrderShip saleOrderShip) {
        boolean rtn = false;
        Date now = Calendar.getInstance().getTime();
        com.ulife.order.service.dto.PushMainOrderRequest mainOrderDto = new com.ulife.order.service.dto.PushMainOrderRequest();
        mainOrderDto.AppId = appId;
        mainOrderDto.TimeStamp = now.getTime();
        mainOrderDto.TimeStamp = 1430793815L;
        mainOrderDto.DataSign = sign(appId, mainOrderDto.TimeStamp, signKey);
        mainOrderDto.DataSign = "016b2c0d54937acde0058ceef75f9b31";
        mainOrderDto.SoHeader = new ArrayList<>();

        com.ulife.order.service.dto.MainOrderInfo mainOrderInfo = new com.ulife.order.service.dto.MainOrderInfo();
        mainOrderDto.SoHeader.add(mainOrderInfo);
        mainOrderInfo.Action = "C";//C:创建；M：修改
        mainOrderInfo.SaleNo = saleOrder.getSaleNo();
        mainOrderInfo.CustomerId = saleOrder.getCustomerId();
        mainOrderInfo.OrderTime = saleOrder.getOrderTime();
        mainOrderInfo.ConfirmTime = saleOrder.getConfirmTime();
        mainOrderInfo.SaleChannel = saleOrder.getSaleChannel();
        mainOrderInfo.SalerId = saleOrder.getSalerId() == null ? 0 : saleOrder.getSalerId();
        mainOrderInfo.SalerName = saleOrder.getSalerName();
        mainOrderInfo.Status = getSaleOrderStatusName(saleOrder.getStatus());
        mainOrderInfo.PayStatus = getPayStatusName(saleOrder.getPayStatus());
        mainOrderInfo.PayType = saleOrder.getPayType();
        mainOrderInfo.PayChannel = saleOrder.getPayChannel();
        mainOrderInfo.TotalAmount = saleOrder.getTotalAmount() == null ? BigDecimal.ZERO : saleOrder.getTotalAmount();
        mainOrderInfo.SubAmount = saleOrder.getSubAmount();
        mainOrderInfo.PaidAmount = saleOrder.getPaidAmount() == null ? BigDecimal.ZERO : saleOrder.getPaidAmount();
        mainOrderInfo.ShipStatus = saleOrder.getShipStatus();
        mainOrderInfo.ShipDate = saleOrder.getShipDate();
        mainOrderInfo.ShipFee = (saleOrder.getShipFee().subtract(saleOrder.getShipFeeDiscount()));
        mainOrderInfo.ShipFeeDiscount = saleOrder.getShipFeeDiscount() == null ? BigDecimal.ZERO : saleOrder.getShipFeeDiscount();
        mainOrderInfo.PromotionDiscount = (saleOrder.getPromotionDiscount().add(saleOrder.getProductCouponDiscount()));
        mainOrderInfo.Terminal = saleOrder.getTerminal();
        mainOrderInfo.Source = saleOrder.getSource();
        mainOrderInfo.ModifiedTime = saleOrder.getModifiedTime();
        mainOrderInfo.ModifiedBy = saleOrder.getModifiedBy();
        mainOrderInfo.CreatedTime = saleOrder.getCreatedTime();
        mainOrderInfo.CreatedBy = saleOrder.getCreatedBy();
        mainOrderInfo.StartShipDate = saleOrder.getStartShipDate();
        mainOrderInfo.ShipFrequance = saleOrder.getShipFrequency();
        mainOrderInfo.Consignee = saleOrderShip.getConsignee();
        mainOrderInfo.Mobile = saleOrderShip.getMobile();
        mainOrderInfo.Privince = saleOrderShip.getPrivince();
        mainOrderInfo.City = saleOrderShip.getCity();
        mainOrderInfo.CityZone = saleOrderShip.getCityZone();
        mainOrderInfo.AddressDetail = saleOrderShip.getDetail();

        String requestJsonString = null;

        requestJsonString = com.ulife.order.service.util.JsonUtils.obj2Json(mainOrderDto);

        String responseJsonString = com.ulife.order.service.util.HttpUtil.httpPost(mainUrl, requestJsonString, Charset.forName("utf-8"), "application/json");
        if (responseJsonString == null || responseJsonString.isEmpty()) return false;
        logger.info(responseJsonString);

        com.ulife.order.service.dto.PushOrderResponse response = com.ulife.order.service.util.JsonUtils.json2Obj(responseJsonString, com.ulife.order.service.dto.PushOrderResponse.class);
        return parseResponse(response);
    }

    /*
    * sale order pay status 名称
    * */
    private String getPayStatusName(int payStatus) {
        SaleOrderPayStatus status = com.ulife.order.service.enumeration.SaleOrderPayStatus.valueOf(payStatus);
        switch (status) {
            case WaitPay:
                return "未支付";
            case PartialPay:
                return "部分支付";
            case Paid:
                return "已支付";
            default:
                return "";
        }
    }


    /*
    * sale order status 名称
    * */
    private String getSaleOrderStatusName(int status) {
        SaleOrderStatus saleOrderStatus = SaleOrderStatus.valueOf(status);
        switch (saleOrderStatus) {
            case Created:
                return "已创建";
            case Confirmed:
                return "已确认";
            case Splited:
                return "已拆单";
            default:
                return "";
        }
    }

    /*
    * 推送子订单
    * */
    private boolean pushSub(SaleOrder saleOrder, List<SaleOrderItem> saleOrderItemList, SaleOrderShip saleOrderShip, List<SaleOrderPay> saleOrderPayList,List<SaleOrderItemPromotion> saleOrderItemPromotionList) throws ServiceException {
        boolean rtn = false;
        Date now = Calendar.getInstance().getTime();
        logger.info("in push sub order");
        com.ulife.order.service.dto.PushSubOrderRequest subOrderDto = new com.ulife.order.service.dto.PushSubOrderRequest();
        subOrderDto.AppId = appId;
        subOrderDto.TimeStamp = now.getTime();//todo
        subOrderDto.TimeStamp = 1430793815L;
        subOrderDto.DataSign = sign(appId, subOrderDto.TimeStamp, signKey);//todo
        subOrderDto.DataSign = "016b2c0d54937acde0058ceef75f9b31";

        subOrderDto.SoHeader = new ArrayList<>();
        com.ulife.order.service.dto.SubOrderInfo subOrderInfo = new com.ulife.order.service.dto.SubOrderInfo();
        subOrderInfo.Items = new ArrayList<>();
        subOrderInfo.PayLogs = new ArrayList<>();

        subOrderDto.SoHeader.add(subOrderInfo);
        subOrderInfo.OrderNo = saleOrder.getSaleNo();
        subOrderInfo.OrderType = "普通订单";//saleOrder.getOrderCategory(); //getOrderTypeAlias(saleOrder.getOrderType());
        subOrderInfo.OrderStatus = getSaleOrderStatusName(saleOrder.getStatus());
        subOrderInfo.MainOrderNo = saleOrder.getPackageSaleNo();
        subOrderInfo.PayStatus = getPayStatusName(saleOrder.getPayStatus());
        subOrderInfo.PaymentType = saleOrder.getPayType();
        subOrderInfo.PaymentMeth = saleOrder.getPayChannel();
        subOrderInfo.TotalAmount = saleOrder.getTotalAmount().toString();
        subOrderInfo.PaidAmount = saleOrder.getPaidAmount().toString();
        subOrderInfo.RefundAmount = "0";
        subOrderInfo.SubTotal = saleOrder.getSubAmount().toString();
        subOrderInfo.ShipFee = saleOrder.getShipFee().toString();
        subOrderInfo.ShipFeeDiscount = saleOrder.getShipFeeDiscount().abs().add(saleOrder.getShipFeeCouponDiscount().abs()).toString();
        subOrderInfo.CouponDiscount = saleOrder.getProductCouponDiscount().toString();
        subOrderInfo.PromotionDiscount = saleOrder.getPromotionDiscount().toString();
        subOrderInfo.OrderDate = saleOrder.getOrderTime();
        subOrderInfo.Channel = getChannelAlias(saleOrder.getSaleChannel(), saleOrder.getTerminal());
        subOrderInfo.DeliveryLimit = saleOrder.getShipDate();
        subOrderInfo.CustomerId = saleOrder.getCustomerId().toString();
//        subOrderInfo.CustomerLoginName = saleOrder.getCustomerId().toString();
        subOrderInfo.CarrierId = "";
        subOrderInfo.Consignee = saleOrderShip.getConsignee();
        subOrderInfo.MobileNo = saleOrderShip.getMobile();
        subOrderInfo.PhoneNo = "";
        subOrderInfo.Remark = "";
        subOrderInfo.Province = saleOrderShip.getPrivince();
        subOrderInfo.City = saleOrderShip.getCity();
        subOrderInfo.CityZone = saleOrderShip.getCityZone();
        subOrderInfo.Zipcode = "";
        subOrderInfo.AddressDetail = saleOrderShip.getDetail();
        subOrderInfo.OrderCatetory=saleOrder.getOrderCategory();
        for (SaleOrderItem saleOrderItem : saleOrderItemList) {
            ProductMoreResponse productMoreResponse = productService.getMoreInfo(saleOrderItem.getItemId());
            if (productMoreResponse.ispackage) {
                productMoreResponse.subProducts.sort(new Comparator<SubProductMoreDTO>() {
                    //先按qty递减，再按id
                    @Override
                    public int compare(SubProductMoreDTO o1, SubProductMoreDTO o2) {
                        int temp = o1.getQty() - o2.getQty();
                        long tempSub = o1.getId() - o2.getQty();

                        return temp > 0 ? 1 : (temp == 0 ? (tempSub > 0 ? 1 : (tempSub == 0 ? 0 : -1)) : -1);
                    }
                });
                Map<Long, Double> priceShare = getShareUnitPrice(saleOrderItem.getUnitPrice().doubleValue(), productMoreResponse.subProducts);
                List<SaleOrderItemPromotion> itemPromotionMap=  dispatchPromotionByItemID(saleOrderItem,saleOrderItemPromotionList);
                for (SubProductMoreDTO subProduct : productMoreResponse.subProducts) {
                    Item item = new Item();
                    item.SoNo = saleOrderItem.getSoNo();
                    item.OrderQty = saleOrderItem.getQuantity() * subProduct.getQty();
                    item.ProductId = subProduct.getSkuId();
                    item.ProductCode = String.valueOf(subProduct.getProductCode());
                    item.ProductCodeExt = "";
                    item.ProductName = subProduct.getSkuName();
                    item.Remark = "";
                    item.UnitPrice = priceShare.containsKey(subProduct.getId()) ? priceShare.get(subProduct.getId()) : 0d;
                    item.OrignalUnitPrice = subProduct.getRrp();//rrp
                    item.PackageCode = "";
                    item.PackageCodeExt = "";
                    item.PackageName = productMoreResponse.skuName;
                    item.PackageProductId = productMoreResponse.getSkuId();
                    item.Point = 0L;
                    item.ItemPromotions=new ArrayList<>();
                    for(SaleOrderItemPromotion itemPromotion:itemPromotionMap)
                    {
                        if(saleOrderItem.getId().equals(itemPromotion.getSoItemId()) && subProduct.getSkuId()==itemPromotion.getPackitemId())
                        {
                            ItemPromotion promo = new ItemPromotion();
                            promo.Discount = itemPromotion.getDiscount();
                            promo.PromotionId = itemPromotion.getPromotionId();
                            promo.CreatedTime = itemPromotion.getCreatedTime();
                            promo.ModifiedTime = itemPromotion.getModifiedTime();
                            promo.SoNo = itemPromotion.getSoNo();
                            item.ItemPromotions.add(promo);
                        }
                    }
                    subOrderInfo.Items.add(item);
                }
            } else {
                Item item = new Item();
                item.SoNo = saleOrderItem.getSoNo();
                item.ProductId = saleOrderItem.getSkuId();
                item.ProductName = saleOrderItem.getSkuName();
                item.ProductCode = saleOrderItem.getSkuCode();
                item.OrderQty = saleOrderItem.getQuantity();
                item.UnitPrice = saleOrderItem.getUnitPrice().doubleValue();//realprice
                item.OrignalUnitPrice = saleOrderItem.getOrignalUnitPrice() == null ? saleOrderItem.getUnitPrice().doubleValue() : saleOrderItem.getOrignalUnitPrice().doubleValue();//realprice
                item.PackageCode = "";
                item.PackageCodeExt = "";
                item.PackageName = "";
                item.PackageProductId = 0L;
                item.Point = 0L;
                item.Remark = "";
                item.ProductCodeExt = "";
                item.ItemPromotions=new ArrayList<>();
                for(SaleOrderItemPromotion itemPromotion:saleOrderItemPromotionList)
                {
                    if(saleOrderItem.getId().equals(itemPromotion.getSoItemId())) {
                        ItemPromotion promo = new ItemPromotion();
                        promo.Discount = itemPromotion.getDiscount();
                        promo.PromotionId = itemPromotion.getPromotionId();
                        promo.CreatedTime = itemPromotion.getCreatedTime();
                        promo.ModifiedTime = itemPromotion.getModifiedTime();
                        promo.SoNo = itemPromotion.getSoNo();
                        item.ItemPromotions.add(promo);
                    }
                }
                subOrderInfo.Items.add(item);
            }
        }

        for (SaleOrderPay saleOrderPay : saleOrderPayList) {
            PayLogInfo payLogInfo = new PayLogInfo();
            payLogInfo.Amount = saleOrderPay.getAmount();
            //payLogInfo.BankOrderNumber = saleOrderPay.getBankSerialNo();
            payLogInfo.BankOrderNumber = saleOrderPay.getTxSerialNumber();
            payLogInfo.IsSuccess = saleOrderPay.getStatus().intValue() == PayStatus.Success.value() ? 1 : 0;
            payLogInfo.PaymentType = saleOrderPay.getPayChannel();
            payLogInfo.SoNo = saleOrderPay.getSoNo();
            payLogInfo.CreatedTime=saleOrderPay.getCreatedTime();
            payLogInfo.ModifiedTime=saleOrderPay.getModifiedTime();
            subOrderInfo.PayLogs.add(payLogInfo);
        }

//        for(SaleOrderItemPromotion saleOrderItemPromotion:saleOrderItemPromotionList){
//            ItemPromotion  promotion=new ItemPromotion();
//            promotion.Discount=saleOrderItemPromotion.getDiscount();
//            promotion.PromotionId=saleOrderItemPromotion.getPromotionId();
//            promotion.CreatedTime=saleOrderItemPromotion.getCreatedTime();
//            promotion.ModifiedTime=saleOrderItemPromotion.getModifiedTime();
//            promotion.SoNo=saleOrderItemPromotion.getSoNo();
//            subOrderInfo.ItemPromotions.add(promotion);
//        }

        String requestJsonString = null;
        requestJsonString = JsonUtils.obj2Json(subOrderDto);
        logger.info("push sub order, request = " + requestJsonString);
        String responseJsonString = HttpUtil.httpPost(subUrl, requestJsonString, Charset.forName("utf-8"), "application/json");
        logger.info("push sub order, response = " + responseJsonString);
        if (responseJsonString == null || responseJsonString.isEmpty()) return false;

        PushOrderResponse response = JsonUtils.json2Obj(responseJsonString, PushOrderResponse.class);
        return parseResponse(response);
    }

    /*
    * channel映射到OM的channel
    * */
    private String getChannelAlias(String channel, String terminal) {
        if (channel.isEmpty()) return "";
        switch (channel.toUpperCase()) {
            case TerminalConst.ANDROID:
                return OMChannelConst.APP;
            case TerminalConst.IOS:
                return OMChannelConst.APP;
            case TerminalConst.H5:
                return OMChannelConst.WAP;
            case TerminalConst.PC:
                return OMChannelConst.WEB;
            default:
                return channel;
        }
    }


    /*
    * 拆分商品价格比例
    * package unit price 礼包价格
    * List<ProductMoreResponse.SubProduct> 礼包子商品列表，已按qty、id排序
    * Map<Long,Double> 礼包子商品拆分后单价
    * packageUnitPrice = (2 + 6 + 12 = 20 - 2) = 18
    * 3:4:3 ===>3.6
    * 2:3,2 ===>2.7
    * 1:2,1 ===>1.8
    * */
    private Map<Long, Double> getShareUnitPrice(double packageUnitPrice, List<SubProductMoreDTO> subProducts) {
        Map<Long, Double> rtn = new HashMap<>();
        double sum = 0d;//20
        double preSum = 0d;

        for (int i = 0; i < subProducts.size(); i++) {
            SubProductMoreDTO sp = subProducts.get(i);
            sum += sp.getRrp() * sp.getQty();
        }

        for (int i = 0; i < subProducts.size(); i++) {
            SubProductMoreDTO sp = subProducts.get(i);

            if (i == subProducts.size() - 1) {//最后一个商品
                double left = packageUnitPrice - preSum;//1.8
                double sharedUnitPrice = left / sp.getQty();//1.8
                BigDecimal b = new BigDecimal(sharedUnitPrice);
                sharedUnitPrice = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();//保留2位小数点
                rtn.put(sp.getId(), sharedUnitPrice);
            } else {
                double currentSum = packageUnitPrice * sp.getRrp() * sp.getQty() / sum;//18*12/20=10.8，5.4
                preSum += currentSum;//10.8,5.4=16.2

                double sharedUnitPrice = currentSum / sp.getQty();//3.6,2.7
                BigDecimal b = new BigDecimal(sharedUnitPrice);
                sharedUnitPrice = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();//保留2位小数点

                rtn.put(sp.getId(), sharedUnitPrice);
            }
        }

        return rtn;
    }

    /*
    * 解析结果
    * */
    private boolean parseResponse(PushOrderResponse response) {
        if (response == null) {
            return false;
        }
        return response.Success || (!response.Success && response.ErrorList != null && response.ErrorList.size() > 0 && response.ErrorList.get(0).ReturnValue.equals("0"));
    }

    //endregion

    //region 拆单
    /*
    * 拆分订单
    * */
    public String split() {
        logger.info("start split method");

        String rtn = "";
        splitLock.lock();
        try {
            int cancelOrderSpan = getSyncTimeSpan();
            Calendar now = Calendar.getInstance();
            Calendar preSplit = Calendar.getInstance();

            preSplit.set(Calendar.MINUTE, preSplit.get(Calendar.MINUTE) - cancelOrderSpan);

            SaleOrderCriteria saleOrderCriteria = new SaleOrderCriteria();
            saleOrderCriteria.createCriteria()
                    .andOrderTypeEqualTo(SaleOrderTypeConst.MAIN_SALE_ORDER)
                    .andSplitEnableEqualTo(1)
                    .andConfirmTimeLessThan(preSplit.getTime())
                    .andIsDeleteEqualTo(0)
                    .andStatusEqualTo(SaleOrderStatus.Confirmed.value());

            saleOrderCriteria.or().andPayTypeEqualTo(COD_NAME)
                    .andOrderTypeEqualTo(SaleOrderTypeConst.MAIN_SALE_ORDER)
                    .andSplitEnableEqualTo(1)
                    .andOrderTimeLessThan(preSplit.getTime())
                    .andIsDeleteEqualTo(0)
                    .andStatusEqualTo(SaleOrderStatus.Created.value());

            List<SaleOrder> saleOrderList = saleOrderLogic.list(saleOrderCriteria);
            if (saleOrderList == null || saleOrderList.size() == 0) {
                return rtn;
            }
            for (SaleOrder saleOrder : saleOrderList) {
                if (saleOrder == null || saleOrder.getSplitEnable().intValue() == 0) continue;
                try {
                    split(saleOrder);
                } catch (Exception e) {
                    logger.error("拆分订单异常 sale_order_no = " + saleOrder.getSaleNo());
                    logger.error(e.toString(), e);
                }
            }
        } finally {
            splitLock.unlock();
        }
        return rtn;
    }

    /*
    * 拆分单个订单
    * */
    @Transactional(rollbackFor = {ServiceException.class})
    private void split(SaleOrder saleOrder) throws ServiceException {

        SaleOrderCriteria saleOrderCriteria = new SaleOrderCriteria();
        saleOrderCriteria.createCriteria().andPackageSaleNoEqualTo(saleOrder.getSaleNo());
        List<SaleOrder> subList = saleOrderLogic.list(saleOrderCriteria);
        if (subList != null && subList.size() > 0) {
            sendOrderExceptionMail("订单拆分","订单拆分错误.错误订单号：" + saleOrder.getSaleNo());
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_SPLIT_ERROR);
        }

        boolean rst = splitSubOrder(saleOrder);
        if (!rst) {
            logger.warn("split order fail ! so_no = " + saleOrder.getSaleNo());
            sendOrderExceptionMail("订单拆分","订单拆分错误.错误订单号：" + saleOrder.getSaleNo());
            return;
        }
        logger.info("6change sale order status from " + saleOrder.getStatus() + " to " + SaleOrderStatus.Splited.value());
        saleOrder.setStatus(SaleOrderStatus.Splited.value());
        saleOrderLogic.update(saleOrder);
    }

    /*
    * 获取延迟取消时效
    * */
    private int getSyncTimeSpan() {

        int rtn = Integer.valueOf(orderCancelPermit);

        Calendar calendar = Calendar.getInstance();
        String[] limitTime = orderCancelPermitLimit.split(",");
        if (limitTime == null || limitTime.length != 3) {
            return rtn;
        }
        String nowTime = calendar.get(Calendar.HOUR) + ":" + calendar.get(Calendar.MINUTE) + ":" + calendar.get(Calendar.SECOND);
        if (limitTime[0].compareToIgnoreCase(nowTime) > 0 && limitTime[1].compareToIgnoreCase(nowTime) < 0) {
            return Integer.valueOf(limitTime[2]);
        }

        return rtn;
    }

    /*
    * 拆分子订单
    * */
    private boolean splitSubOrder(SaleOrder saleOrder) throws ServiceException {
        boolean rtn = true;

        if (saleOrder == null) {
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_NOT_FOUND);
        }
        SaleOrderItemCriteria saleOrderItemCriteria = new SaleOrderItemCriteria();
        saleOrderItemCriteria.createCriteria().andSoNoEqualTo(saleOrder.getSaleNo());
        List<SaleOrderItem> saleOrderItems = saleOrderItemLogic.list(saleOrderItemCriteria);
        if (saleOrderItems == null || saleOrderItems.size() == 0) {
            sendOrderExceptionMail("订单拆分","订单拆分错误.错误订单号：" + saleOrder.getSaleNo());
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_ITEM_NOT_EXIST);
        }

        SortedMap<String, List<SaleOrderItem>> itemMap = new TreeMap<>();//key:provider code
        int i = 1;
        for (SaleOrderItem saleOrderItem : saleOrderItems) {
            //String key = saleOrderItem.getItemForm().equalsIgnoreCase(com.ulife.order.service.componentConst.ProductFormConst.PROVIDER) ? saleOrderItem.getItemSupplier() : saleOrderItem.getItemForm();
            String key = saleOrderItem.getItemForm().equalsIgnoreCase(com.ulife.order.service.componentConst.ProductFormConst.PROVIDER) ? (ProductFormConst.PROVIDER + "_" + i++) : saleOrderItem.getItemForm();//供应商直发的商品，每个商品做一个订单
            if (!itemMap.containsKey(key)) {
                itemMap.put(key, new ArrayList<>());
            }
            List<SaleOrderItem> list = itemMap.get(key);
            list.add(saleOrderItem);
            itemMap.put(key, list);
        }

        rtn = SaveSubOrder(saleOrder, itemMap);

        return rtn;
    }

    /*
    * 获取sale_order_item_promotion
    * */
    private BigDecimal getItemPromotion(List<SaleOrderItemPromotion> saleOrderItemPromotions, Long soItemId) {
        BigDecimal rtn = BigDecimal.ZERO;
        for (SaleOrderItemPromotion saleOrderItemPromotion : saleOrderItemPromotions) {
            if (saleOrderItemPromotion.getSoItemId().longValue() == soItemId.longValue() && saleOrderItemPromotion.getPromotionId().longValue() > 0) {//仅限优惠金额
                rtn = rtn.add(saleOrderItemPromotion.getDiscount());
                logger.info("item promotion is:".concat(rtn.toString()));
            }
        }
        return rtn;
    }

    /*
    * 获取sale_order_item_coupon_promotion
    * */
    private BigDecimal getItemCouponPromotion(List<SaleOrderItemPromotion> saleOrderItemPromotions, Long soItemId) {
        BigDecimal rtn = BigDecimal.ZERO;
        for (SaleOrderItemPromotion saleOrderItemPromotion : saleOrderItemPromotions) {
            if (saleOrderItemPromotion.getSoItemId().longValue() == soItemId.longValue() && saleOrderItemPromotion.getCouponCode().length() > 0 && !saleOrderItemPromotion.getCouponCode().equalsIgnoreCase("0")) {//仅限优惠券优惠金额
                rtn = rtn.add(saleOrderItemPromotion.getDiscount());
                logger.info("item promotion is:".concat(rtn.toString()));
            }
        }
        return rtn;
    }

    /*
    * 保存子订单
    * */
    private boolean SaveSubOrder(SaleOrder saleOrder, Map<String, List<SaleOrderItem>> itemMap) throws ServiceException {//itemMap:key:provider code
        boolean rtn = true;
        Date now = Calendar.getInstance().getTime();

        SaleOrderItemPromotionCriteria saleOrderItemPromotionCriteria = new SaleOrderItemPromotionCriteria();
        saleOrderItemPromotionCriteria.createCriteria().andSoNoEqualTo(saleOrder.getSaleNo());
        List<SaleOrderItemPromotion> saleOrderItemPromotionList = saleOrderItemPromotionLogic.list(saleOrderItemPromotionCriteria);
        if (saleOrderItemPromotionList == null) saleOrderItemPromotionList = new ArrayList<>();

        SaleOrderShipCriteria saleOrderShipCriteria = new SaleOrderShipCriteria();
        saleOrderShipCriteria.createCriteria().andSoNoEqualTo(saleOrder.getSaleNo());
        List<SaleOrderShip> saleOrderShipList = saleOrderShipLogic.list(saleOrderShipCriteria);
        if (saleOrderShipList == null || saleOrderShipList.size() <= 0) {
            sendOrderExceptionMail("订单拆分","订单保存子订单错误.订单没有收货信息.错误订单号：" + saleOrder.getSaleNo());
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_SHIP_NOT_FOUND);
        }

        SaleOrderPayCriteria saleOrderPayCriteria = new SaleOrderPayCriteria();
        saleOrderPayCriteria.createCriteria().andSoNoEqualTo(saleOrder.getSaleNo()).andStatusEqualTo(PayStatus.Success.value());
        List<SaleOrderPay> saleOrderPayList = saleOrderPayLogic.list(saleOrderPayCriteria);
        if (saleOrderPayList == null) saleOrderPayList = new ArrayList<>();
        if (!saleOrder.getPayType().equalsIgnoreCase(COD_NAME) && saleOrderPayList.size() == 0) {//非货到付款，必有pay信息
            sendOrderExceptionMail("订单拆分","订单保存子订单错误.订单非货到付款，必须有支付信息.错误订单号：" + saleOrder.getSaleNo());
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_PAY_NOT_EXIST);
        }
        saleOrderPayList.sort(new Comparator<SaleOrderPay>() {
            @Override
            public int compare(SaleOrderPay o1, SaleOrderPay o2) {
                return o1.getPayChannel().compareTo(o2.getPayChannel());
            }
        });


        Map<String, BigDecimal> amountMap = new HashMap<>();
        Map<String, SaleOrder> orderMap = new HashMap<>();//orderMap:key:provider code
        for (String key : itemMap.keySet()) {//itemMap:key:provider code
            try {
                SaleOrder subSaleOrder = new SaleOrder();
                dozerBeanMapper.map(saleOrder, subSaleOrder);
                subSaleOrder.setId(0L);
                subSaleOrder.setOrderType(com.ulife.order.service.componentConst.SaleOrderTypeConst.SUB_SALE_ORDER);
                subSaleOrder.setSaleNo(memberService.generateOrderNo());
                subSaleOrder.setPackageSaleNo(saleOrder.getSaleNo());
                subSaleOrder.setConfirmTime(saleOrder.getConfirmTime());
                subSaleOrder.setCreatedTime(now);
                subSaleOrder.setStatus(saleOrder.getStatus());
                //subSaleOrder.setOrderCategory("普通订单"); // add by dang 2016/04/27   产品李超提出，所有同步到OM的单子都为普通订单
                subSaleOrder.setOrderCategory(saleOrder.getOrderCategory());

                subSaleOrder.setShipFee(BigDecimal.ZERO);
                subSaleOrder.setSubAmount(BigDecimal.ZERO);
                subSaleOrder.setTotalAmount(BigDecimal.ZERO);
                subSaleOrder.setProductCouponDiscount(BigDecimal.ZERO);
                subSaleOrder.setPromotionDiscount(BigDecimal.ZERO);
                subSaleOrder.setShipFeeDiscount(BigDecimal.ZERO);
                subSaleOrder.setShipFeeCouponDiscount(BigDecimal.ZERO);
                subSaleOrder.setPaidAmount(BigDecimal.ZERO);

                List<SaleOrderItem> items = itemMap.get(key);
                List<SaleOrderItem> targetItems = new ArrayList<>();//target sub order item
                BigDecimal item_promotion_amount = BigDecimal.ZERO;
                BigDecimal item_coupon_promotion_amount = BigDecimal.ZERO;
                for (SaleOrderItem saleOrderItem : items) {
                    SaleOrderItem targetItem = new SaleOrderItem();
                    dozerBeanMapper.map(saleOrderItem, targetItem);
                    targetItem.setId(0L);
                    targetItem.setSoNo(subSaleOrder.getSaleNo());
                    targetItem.setCreatedTime(now);
                    targetItems.add(targetItem);

                    //item总金额 = 商品unit_price * qty
                    BigDecimal item_amount = targetItem.getUnitPrice().multiply(BigDecimal.valueOf(targetItem.getQuantity()));
                    //商品总金额 = sum(item总金额)
                    subSaleOrder.setSubAmount(subSaleOrder.getSubAmount().add(item_amount));
                    //item 优惠金额
                    item_promotion_amount = item_promotion_amount.add(getItemPromotion(saleOrderItemPromotionList, saleOrderItem.getId()));
                    //item 优惠券金额
                    item_coupon_promotion_amount = item_coupon_promotion_amount.add(getItemCouponPromotion(saleOrderItemPromotionList, saleOrderItem.getId()));
                }
                if (key.equalsIgnoreCase(ProductFormConst.SELF)) {//只有自营才有运费todo
                    subSaleOrder.setShipFee(saleOrder.getShipFee());
                } else {
                    //供应商直发订单，配送日期默认规则（18：00点前下单，配送日期T+1，18：00点后配送日期T+2）
                    //产品部 160415 修改：提出 12点为结单点  T+2  T+3
                    Calendar instance = Calendar.getInstance();
                    instance.setTime(saleOrder.getConfirmTime());
                    if (instance.get(Calendar.HOUR_OF_DAY) >= 12 ) {//T+3
                        instance.add(Calendar.DATE, 3);
                    } else {//T+2
                        instance.add(Calendar.DATE, 2);
                    }
                    subSaleOrder.setShipDate(instance.getTime());
                    subSaleOrder.setSaleChannel(SaleChannelConst.ONLINE_DIRECT);
                    logger.warn("sub order sale channel is online_direct");
                }
                //如果只有一个子单，则不用算，直接把主单优惠金额汇总到子单上
                if (itemMap.size() == 1) {//for fix promotion dicount miss bug
                    subSaleOrder.setPromotionDiscount(saleOrder.getPromotionDiscount().abs());
                    subSaleOrder.setProductCouponDiscount(saleOrder.getProductCouponDiscount().abs());
                    subSaleOrder.setShipFeeDiscount(saleOrder.getShipFeeDiscount().abs());
                    subSaleOrder.setShipFeeCouponDiscount(saleOrder.getShipFeeCouponDiscount());
                } else {
                    subSaleOrder.setPromotionDiscount(item_promotion_amount.abs());
                    subSaleOrder.setProductCouponDiscount(item_coupon_promotion_amount.abs());
                }
                //subSaleOrder.setTotalAmount(subSaleOrder.getSubAmount().add(subSaleOrder.getShipFee()).subtract(item_promotion_amount.abs()).subtract(saleOrder.getShipFeeDiscount()));
                //订单总金额 total amount = sub amount + ship fee - promotion discount - product coupon discount - ship fee discount - ship fee coupon discount
                subSaleOrder.setTotalAmount(subSaleOrder.getSubAmount().abs().add(subSaleOrder.getShipFee().abs()).subtract(subSaleOrder.getPromotionDiscount().abs()).subtract(subSaleOrder.getProductCouponDiscount().abs()).subtract(subSaleOrder.getShipFeeDiscount().abs()).subtract(subSaleOrder.getShipFeeCouponDiscount().abs()));//ship fee dicount always equal zero
                subSaleOrder.setPaidAmount(saleOrder.getPayType().equalsIgnoreCase(COD_NAME) ? BigDecimal.ZERO : subSaleOrder.getTotalAmount());//主单为货到付款，则子单paidamount = 0

                saleOrderLogic.insert(subSaleOrder);
                if (targetItems == null || targetItems.size() == 0) {
                    logger.warn("sub order item count is 0.");
                    throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_SPLIT_ERROR);
                }
                targetItems.forEach(saleOrderItemLogic::insert);

                SaleOrderShip saleOrderShip = new SaleOrderShip();
                dozerBeanMapper.map(saleOrderShipList.get(0), saleOrderShip);
                saleOrderShip.setId(0L);
                saleOrderShip.setSoNo(subSaleOrder.getSaleNo());
                saleOrderShip.setCreatedTime(now);
                saleOrderShipLogic.insert(saleOrderShip);

                orderMap.put(key, subSaleOrder);//orderMap:key:provider code
            } catch (Exception e) {
                logger.error(e.toString(), e);
                sendOrderExceptionMail("订单拆分","订单保存子订单错误.订单号：" + saleOrder.getSaleNo()+" 错误信息:"+e.toString());
                throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_SPLIT_ERROR);
            }
        }

        //key:self/song/tang；value:subSaleOrder pay list
        Map<String, List<SaleOrderPay>> orderPayMap = dispatchPay(orderMap, saleOrderPayList);//orderMap:key:provider code
        for (String key : orderMap.keySet()) {
            List<SaleOrderPay> subSaleOrderPays = orderPayMap.get(key);
            if (subSaleOrderPays != null && subSaleOrderPays.size() > 0) {
                subSaleOrderPays.forEach(saleOrderPayLogic::insert);
            }
        }
        // save subSaleOrder itempromotion list
        List<SaleOrderItemPromotion> itemPromotionMap=dispatchPromotionForSplit(orderMap,saleOrderItemPromotionList);
        if(itemPromotionMap !=null && itemPromotionMap.size()>0) {
            itemPromotionMap.forEach(saleOrderItemPromotionLogic::insert);
        }
        return rtn;
    }

    /*
    * 拆分支付
    * key:sub order provider code；value:list of sale order pay
    * */
    private Map<String, List<SaleOrderPay>> dispatchPay(Map<String, SaleOrder> orderMap, List<SaleOrderPay> saleOrderPayList) {//orderMap:key:provider code
        Map<String, List<SaleOrderPay>> rtn = new HashMap<>();//rtn:key:sub order provider code
        if (saleOrderPayList == null || saleOrderPayList.size() == 0) return rtn;
        //一个支付方式
        if (saleOrderPayList.size() == 1) {
            SaleOrderPay saleOrderPay = saleOrderPayList.get(0);
            for (String key : orderMap.keySet()) {
                List<SaleOrderPay> list = new ArrayList<>();

                SaleOrder saleOrder = orderMap.get(key);
                SaleOrderPay temp = buildSaleOrderPay(saleOrderPay, saleOrder, saleOrder.getPaidAmount());
                list.add(temp);
                rtn.put(key, list);//rtn:key:sub order provider code
                logger.info("1dispatchPay  key = " + key);
            }
            return rtn;
        }

        //多个支付方式
        Map<String, List<SaleOrderPay>> saleOrderPayMap = new HashMap<>();//key = pay channel
        for (SaleOrderPay saleOrderPay : saleOrderPayList) {
            String key = saleOrderPay.getPayChannel().toLowerCase();
            List<SaleOrderPay> list = new ArrayList<>();
            if (saleOrderPayMap.containsKey(key)) {
                list = saleOrderPayMap.get(key);
            }
            list.add(saleOrderPay);
            saleOrderPayMap.put(key, list);
        }

        Map<String, String> orderProviderMap = new HashMap<>();//key:order sale_no; value:order provider code
        //对sub sale order 排序，自营的排前面
        SaleOrder[] subSaleOrders = new SaleOrder[orderMap.size()];
        int idx = 0;
        if (orderMap.containsKey(ProductFormConst.SELF)) {//有自营的自订单
            subSaleOrders[idx] = orderMap.get(ProductFormConst.SELF);//第一个为自营子订单
            orderProviderMap.put(subSaleOrders[idx].getSaleNo(), ProductFormConst.SELF);//key:order sale_no; value:order provider code
            idx++;
        }
        for (Map.Entry<String, SaleOrder> entry : orderMap.entrySet()) {
            if (entry.getKey().equalsIgnoreCase(ProductFormConst.SELF)) continue;
            subSaleOrders[idx] = entry.getValue();
            orderProviderMap.put(subSaleOrders[idx].getSaleNo(), ProductFormConst.SELF);//key:order sale_no; value:order provider code
            idx++;
        }
        //对sale order pay 排序，balance的排前面
        idx = 0;
        SaleOrderPay[] saleOrderPays = new SaleOrderPay[saleOrderPayList.size()];
        if (saleOrderPayMap.containsKey(PAY_CHANNEL_BALANCE)) {
            List<SaleOrderPay> list = saleOrderPayMap.get(PAY_CHANNEL_BALANCE);
            for (SaleOrderPay saleOrderPay : list) {
                saleOrderPays[idx] = saleOrderPay;
                idx++;
            }
        }
        for (Map.Entry<String, List<SaleOrderPay>> entry : saleOrderPayMap.entrySet()) {
            if (entry.getKey().equalsIgnoreCase(PAY_CHANNEL_BALANCE)) continue;
            List<SaleOrderPay> list = entry.getValue();
            for (SaleOrderPay saleOrderPay : list) {
                saleOrderPays[idx] = saleOrderPay;
                idx++;
            }
        }

        Map<Long, BigDecimal> payMap = new HashMap<>();//key = sale order pay id
        Map<Long, BigDecimal> saleOrderPaidMap = new HashMap<>();//key = sale order id

        for (int i = 0; i < subSaleOrders.length; i++) {
            for (int j = 0; j < saleOrderPays.length; j++) {

                logger.info("2in dispatchPay  order.saleno = " + subSaleOrders[i].getSaleNo() + " order pay id " + saleOrderPays[j].getId());

                //该sale order pay 已使用的金额
                BigDecimal usedAmount = payMap.containsKey(saleOrderPays[j].getId()) ? payMap.get(saleOrderPays[j].getId()) : BigDecimal.ZERO;
                //该sale order pay amount 已使用完
                if (payMap.containsKey(saleOrderPays[j].getId()) && usedAmount.compareTo(saleOrderPays[j].getAmount()) == 0) {
                    continue;
                }

                //该sale order pay 还是剩下的amount
                BigDecimal leftAmount = saleOrderPays[j].getAmount().subtract(usedAmount);
                //该sub sale order 还需pay的金额
                BigDecimal needPay = saleOrderPaidMap.containsKey(subSaleOrders[i].getId()) ? subSaleOrders[i].getPaidAmount().subtract(saleOrderPaidMap.get(subSaleOrders[i].getId())) : subSaleOrders[i].getPaidAmount();

                //sale order pay left amount正好支付订单
                if (needPay.compareTo(leftAmount) == 0) {
                    logger.info("1dispatchPay  need pay = " + needPay);
                    payMap.put(saleOrderPays[j].getId(), leftAmount);
                    //add saleOrderPay to subSaleOrder
                    SaleOrderPay saleOrderPay = buildSaleOrderPay(saleOrderPays[j], subSaleOrders[i], needPay);
                    //saleOrderPayLogic.insert(saleOrderPay);
                    String key = orderProviderMap.get(subSaleOrders[i].getSaleNo());//orderProviderMap.key:order sale_no; value:order provider code
                    List<SaleOrderPay> list = new ArrayList<>();
                    if (rtn.containsKey(key)) {
                        list = rtn.get(key);
                    }
                    list.add(saleOrderPay);
                    rtn.put(key, list);//rtn:key:sub order provider code
                    logger.info("1dispatchPay  key = " + key);
                    break;
                }
                //sale order pay left amount足够支付订单
                if (needPay.compareTo(leftAmount) < 0) {
                    BigDecimal temp = needPay;
                    if (payMap.containsKey(saleOrderPays[j].getId())) {//把金额累加到已分配中
                        temp = payMap.get(saleOrderPays[j].getId()).add(temp);
                    }
                    payMap.put(saleOrderPays[j].getId(), temp);

//                    if (saleOrderPaidMap.containsKey(subSaleOrders[i].getId())) {//移除该sub sale order
//                        saleOrderPaidMap.remove(subSaleOrders[i].getId());
//                    }
                    //add saleOrderPay to subSaleOrder
                    SaleOrderPay saleOrderPay = buildSaleOrderPay(saleOrderPays[j], subSaleOrders[i], needPay);
//                    saleOrderPayLogic.insert(saleOrderPay);
                    String key = orderProviderMap.get(subSaleOrders[i].getSaleNo());//orderProviderMap.key:order sale_no; value:order provider code
                    List<SaleOrderPay> list = new ArrayList<>();
                    if (rtn.containsKey(key)) {
                        list = rtn.get(key);
                    }
                    list.add(saleOrderPay);
                    rtn.put(key, list);//rtn:key:sub order provider code
                    logger.info("11dispatchPay  key = " + key);
                    break;
                }
                //sale order pay left amount不够支付订单
                if (needPay.compareTo(leftAmount) > 0) {//sub sale order need Paid amount > sale order pay left amount
                    BigDecimal temp = leftAmount;
                    if (payMap.containsKey(saleOrderPays[j].getId())) {//把金额累加到已分配中
                        temp = payMap.get(saleOrderPays[j].getId()).add(temp);
                    }
                    payMap.put(saleOrderPays[j].getId(), temp);

                    temp = leftAmount;
                    if (saleOrderPaidMap.containsKey(subSaleOrders[i].getId())) {//把金额累加到订单已支付金额中
                        temp = saleOrderPaidMap.get(subSaleOrders[i].getId()).add(temp);
                    }
                    saleOrderPaidMap.put(subSaleOrders[i].getId(), temp);

                    //add saleOrderPay to subSaleOrder
                    SaleOrderPay saleOrderPay = buildSaleOrderPay(saleOrderPays[j], subSaleOrders[i], leftAmount);
//                    saleOrderPayLogic.insert(saleOrderPay);
                    String key = orderProviderMap.get(subSaleOrders[i].getSaleNo());//orderProviderMap.key:order sale_no; value:order provider code
                    List<SaleOrderPay> list = new ArrayList<>();
                    if (rtn.containsKey(key)) {
                        list = rtn.get(key);
                    }
                    list.add(saleOrderPay);
                    rtn.put(key, list);//rtn:key:sub order provider code
                    logger.info("111dispatchPay  key = " + key);
                }
            }
        }
        return rtn;
    }

    private SaleOrderPay buildSaleOrderPay(SaleOrderPay original, SaleOrder saleOrder, BigDecimal amount) {
        SaleOrderPay rtn = new SaleOrderPay();
        dozerBeanMapper.map(original, rtn);
        rtn.setId(0L);
        rtn.setSoNo(saleOrder.getSaleNo());
        rtn.setCreatedBy("system");
        rtn.setModifiedTime(Calendar.getInstance().getTime());
        rtn.setAmount(amount);
        return rtn;
    }

    /**
     * 拆单使用
     * @param orderMap
     * @param mainOrderItemPromotionList
     * @return
     * @throws ServiceException
     */
    private List<SaleOrderItemPromotion> dispatchPromotionForSplit(Map<String,SaleOrder> orderMap,List<SaleOrderItemPromotion> mainOrderItemPromotionList)throws  ServiceException
    {
        List<ItemPromotionSplitDTO>  splitDTOs=getPromotionSplitDto(orderMap,mainOrderItemPromotionList);
        List<SaleOrderItemPromotion> list = new ArrayList<>();
        if (splitDTOs == null || splitDTOs.size() == 0) return list;
        for(ItemPromotionSplitDTO promotion:splitDTOs){
            try{
                    SaleOrderItemPromotion itemPromotion=new SaleOrderItemPromotion();
                    itemPromotion.setSoNo(promotion.getSoNo());
                    itemPromotion.setSoItemId(promotion.getSubOrderItemId());
                    itemPromotion.setCouponCode(promotion.getCouponCode());
                    itemPromotion.setPromotionId(promotion.getPromotionId());
                    itemPromotion.setDiscount(promotion.getAmount());
                    itemPromotion.setIsValid(promotion.getIsvalid());
                    itemPromotion.setCreatedBy("system");
                    itemPromotion.setCreatedTime(Calendar.getInstance().getTime());
                    itemPromotion.setModifiedBy("system");
                    itemPromotion.setModifiedTime(Calendar.getInstance().getTime());
                    list.add(itemPromotion);
            }
            catch (Exception ex){
                ex.printStackTrace();
            }
        }
        return  list;
    }

    /***
     * 获取子单itempromotion
     * @param orderMap
     * @param mainOrderItemPromotionList
     * @return
     * @throws ServiceException
     */
    private List<ItemPromotionSplitDTO> getPromotionSplitDto(Map<String,SaleOrder> orderMap,List<SaleOrderItemPromotion> mainOrderItemPromotionList)throws  ServiceException{

        List<ItemPromotionSplitDTO> mainOrderDTOS=new ArrayList<>();//主单优惠商品信息

        List<ItemPromotionSplitDTO> promotionSplitDTOs=new ArrayList<>();
        if (mainOrderItemPromotionList == null || mainOrderItemPromotionList.size() == 0) return promotionSplitDTOs;

        for(SaleOrderItemPromotion main:mainOrderItemPromotionList){
            List<SaleOrderItem> mainlists = getOrderItemList(main.getSoNo());
            for(SaleOrderItem item:mainlists){
                if(item.getId().equals(main.getSoItemId())) {
                    ItemPromotionSplitDTO dto = new ItemPromotionSplitDTO();
                    dto.setSoNo(main.getSoNo());
                    dto.setMainOrderItemId(main.getSoItemId());
                    dto.setItemId(item.getItemId());
                    dto.setAmount(main.getDiscount());
                    dto.setPromotionId(main.getPromotionId());
                    dto.setCouponCode(main.getCouponCode());
                    dto.setItemQty(item.getQuantity());
                    dto.setIsvalid(main.getIsValid());
                    mainOrderDTOS.add(dto);
                }
            }
        }

        for(String key:orderMap.keySet()){
            SaleOrder saleOrder = orderMap.get(key);
            List<SaleOrderItem> saleOrderItemList = getOrderItemList(saleOrder.getSaleNo());
            if(saleOrderItemList ==null && saleOrderItemList.size()==0)return  promotionSplitDTOs;
            for (SaleOrderItem item:saleOrderItemList){
                for(ItemPromotionSplitDTO pro:mainOrderDTOS){
                    if(item.getItemId().equals(pro.getItemId())){
                        ItemPromotionSplitDTO dto=new ItemPromotionSplitDTO();
                        dto.setSoNo(item.getSoNo());
                        dto.setItemId(pro.getItemId());
                        dto.setMainOrderItemId(pro.getMainOrderItemId());
                        dto.setSubOrderItemId(item.getId());
                        dto.setPromotionId(pro.getPromotionId());
                        dto.setCouponCode(pro.getCouponCode());
                        dto.setAmount(pro.getAmount());
                        dto.setItemQty(pro.getItemQty());
                        dto.setIsvalid(pro.getIsvalid());
                        promotionSplitDTOs.add(dto);
                    }
                }
            }
        }
        return  promotionSplitDTOs;
    }

    private List<SaleOrderItemPromotion> dispatchPromotionByItemID(SaleOrderItem items,List<SaleOrderItemPromotion> saleOrderItemPromotionList)throws  ServiceException
    {
        DecimalFormat df = new DecimalFormat("####0.00");
        List<ItemPromotionSplitDTO>  splitDTOs=getPromotionSplitDtoByItemID(items,saleOrderItemPromotionList);
        List<SaleOrderItemPromotion> list = new ArrayList<>();
        if (splitDTOs == null || splitDTOs.size() == 0) return list;
        for(ItemPromotionSplitDTO promotion:splitDTOs){
            try{
                long key=promotion.getMainOrderItemId();
                ProductMoreResponse productMoreResponse = productService.getMoreInfo(promotion.itemId);
                if (productMoreResponse.ispackage) {
                    List<SubProductMoreDTO> itemsDTOs=productMoreResponse.subProducts;
                    //计算商品总金额
                    double allAmount = 0;
                    for (SubProductMoreDTO itemsDTO : itemsDTOs) {
                        allAmount += itemsDTO.getRrp() * itemsDTO.getQty()*promotion.getItemQty();
                    }
                    //已减金额
                    double amount = Double.valueOf(df.format(promotion.getAmount()));
                    //已经分摊的金额
                    double allSplitAmount = 0;
                    for (int i = 0; i < itemsDTOs.size(); i++) {
                        SubProductMoreDTO itemsDTO=itemsDTOs.get(i);
                        SaleOrderItemPromotion itemPromotion=new SaleOrderItemPromotion();
                        itemPromotion.setSoNo(promotion.getSoNo());
                        itemPromotion.setSoItemId(promotion.getSubOrderItemId());
                        itemPromotion.setCouponCode(promotion.getCouponCode());
                        itemPromotion.setPromotionId(promotion.getPromotionId());
                        if (i < (itemsDTOs.size() - 1)) {
                            //按比例分摊金额
                            double itemAmount = itemsDTO.getQty()*itemsDTO.getRrp() * promotion.getItemQty();
                            double splitAmount = Double.valueOf(df.format((itemAmount / allAmount) * amount));
                            itemPromotion.setDiscount(new BigDecimal(splitAmount));
                            allSplitAmount += splitAmount;
                        } else {
                            //如果是最后一个商品，优惠金额减去已分摊金额
                            itemPromotion.setDiscount(new BigDecimal(amount - allSplitAmount));
                        }
                        itemPromotion.setItemId(promotion.getItemId());
                        itemPromotion.setPackitemId(itemsDTO.getSkuId());
                        itemPromotion.setCreatedBy("system");
                        itemPromotion.setCreatedTime(Calendar.getInstance().getTime());
                        itemPromotion.setModifiedBy("system");
                        itemPromotion.setModifiedTime(Calendar.getInstance().getTime());
                        list.add(itemPromotion);
                    }
                }else
                {
                    SaleOrderItemPromotion itemPromotion=new SaleOrderItemPromotion();
                    itemPromotion.setSoNo(promotion.getSoNo());
                    itemPromotion.setSoItemId(promotion.getSubOrderItemId());
                    itemPromotion.setCouponCode(promotion.getCouponCode());
                    itemPromotion.setPromotionId(promotion.getPromotionId());
                    itemPromotion.setDiscount(promotion.getAmount());
                    itemPromotion.setItemId(promotion.getItemId());
                    itemPromotion.setCreatedBy("system");
                    itemPromotion.setCreatedTime(Calendar.getInstance().getTime());
                    itemPromotion.setModifiedBy("system");
                    itemPromotion.setModifiedTime(Calendar.getInstance().getTime());
                    list.add(itemPromotion);
                }
            }
            catch (Exception ex){
                ex.printStackTrace();
            }
        }
        return  list;
    }
    private List<ItemPromotionSplitDTO> getPromotionSplitDtoByItemID(SaleOrderItem items,List<SaleOrderItemPromotion> saleOrderItemPromotionList)throws  ServiceException{

        List<ItemPromotionSplitDTO> mainOrderDTOS=new ArrayList<>();//子单优惠商品信息

        List<ItemPromotionSplitDTO> promotionSplitDTOs=new ArrayList<>();
        if (saleOrderItemPromotionList == null || saleOrderItemPromotionList.size() == 0) return promotionSplitDTOs;
        for(SaleOrderItemPromotion main:saleOrderItemPromotionList){
            List<SaleOrderItem> mainlists = getOrderItemList(main.getSoNo());
            for(SaleOrderItem item:mainlists){
                if(item.getId().equals(main.getSoItemId())) {
                    ItemPromotionSplitDTO dto = new ItemPromotionSplitDTO();
                    dto.setSoNo(main.getSoNo());
                    dto.setMainOrderItemId(main.getSoItemId());
                    dto.setItemId(item.getItemId());
                    dto.setAmount(main.getDiscount());
                    dto.setPromotionId(main.getPromotionId());
                    dto.setCouponCode(main.getCouponCode());
                    dto.setItemQty(item.getQuantity());
                    dto.setIsvalid(main.getIsValid());
                    mainOrderDTOS.add(dto);
                }
            }
        }
            List<SaleOrderItem> saleOrderItemList = getOrderItemList(items.getSoNo());
            if(saleOrderItemList ==null && saleOrderItemList.size()==0)return  promotionSplitDTOs;
            for (SaleOrderItem item:saleOrderItemList){
                for(ItemPromotionSplitDTO pro:mainOrderDTOS){
                    if(item.getItemId().equals(pro.getItemId())){
                        ItemPromotionSplitDTO dto=new ItemPromotionSplitDTO();
                        dto.setSoNo(item.getSoNo());
                        dto.setItemId(pro.getItemId());
                        dto.setMainOrderItemId(pro.getMainOrderItemId());
                        dto.setSubOrderItemId(item.getId());
                        dto.setPromotionId(pro.getPromotionId());
                        dto.setAmount(pro.getAmount());
                        dto.setItemQty(pro.getItemQty());
                        dto.setIsvalid(pro.getIsvalid());
                        promotionSplitDTOs.add(dto);
                    }
                }

        }
        return  promotionSplitDTOs;
    }
    /**
     * 拆分主订单明细优惠均摊到子单商品优惠上
     * @param
     * @param
     * @return
     * 1.一个子单，那么直接把主单的商品对应优惠信息复制到子单的商品对应优惠信息上均分，
     * 2.多个子单就需要将每个子单的item对应的商品的优惠，到主单的对应item商品上优惠均分，
     * */
    private List<SaleOrderItemPromotion> dispatchPromotionForPush(Map<String,SaleOrder> orderMap,List<SaleOrderItemPromotion> mainOrderItemPromotionList)throws  ServiceException
    {
        DecimalFormat df = new DecimalFormat("####0.00");
        List<ItemPromotionSplitDTO>  splitDTOs=getPromotionSplitDto(orderMap,mainOrderItemPromotionList);
        //List<SaleOrderItemPromotion> rtn = new ArrayList<>(); //rtn:key:sub order provider code
        List<SaleOrderItemPromotion> list = new ArrayList<>();
        if (splitDTOs == null || splitDTOs.size() == 0) return list;
        for(ItemPromotionSplitDTO promotion:splitDTOs){
            try{
                long key=promotion.getMainOrderItemId();
                ProductMoreResponse productMoreResponse = productService.getMoreInfo(promotion.itemId);
                if (productMoreResponse.ispackage) {
                    List<SubProductMoreDTO> itemsDTOs=productMoreResponse.subProducts;
                    //计算商品总金额
                    double allAmount = 0;
                    for (SubProductMoreDTO itemsDTO : itemsDTOs) {
                        allAmount += itemsDTO.getRrp() * itemsDTO.getQty()*promotion.getItemQty();
                    }
                    //已减金额
                    double amount = Double.valueOf(df.format(promotion.getAmount()));
                    //已经分摊的金额
                    double allSplitAmount = 0;
                    for (int i = 0; i < itemsDTOs.size(); i++) {
                        SubProductMoreDTO itemsDTO=itemsDTOs.get(i);
                        SaleOrderItemPromotion itemPromotion=new SaleOrderItemPromotion();
                        itemPromotion.setSoNo(promotion.getSoNo());
                        itemPromotion.setSoItemId(promotion.getSubOrderItemId());
                        itemPromotion.setCouponCode(promotion.getCouponCode());
                        itemPromotion.setPromotionId(promotion.getPromotionId());
                        if (i < (itemsDTOs.size() - 1)) {
                            //按比例分摊金额
                            double itemAmount = itemsDTO.getQty()*itemsDTO.getRrp() * promotion.getItemQty();
                            double splitAmount = Double.valueOf(df.format((itemAmount / allAmount)));// * amount));
                            itemPromotion.setDiscount(new BigDecimal(splitAmount));
                            allSplitAmount += splitAmount;
                        } else {
                            //如果是最后一个商品，优惠金额减去已分摊金额
                            itemPromotion.setDiscount(new BigDecimal(amount - allSplitAmount));
                        }
                        itemPromotion.setCreatedBy("system");
                        itemPromotion.setCreatedTime(Calendar.getInstance().getTime());
                        itemPromotion.setModifiedBy("system");
                        itemPromotion.setModifiedTime(Calendar.getInstance().getTime());
                        list.add(itemPromotion);
                    }
                }else
                {
                    SaleOrderItemPromotion itemPromotion=new SaleOrderItemPromotion();
                    itemPromotion.setSoNo(promotion.getSoNo());
                    itemPromotion.setSoItemId(promotion.getSubOrderItemId());
                    itemPromotion.setCouponCode(promotion.getCouponCode());
                    itemPromotion.setPromotionId(promotion.getPromotionId());
                    itemPromotion.setDiscount(promotion.getAmount());
                    itemPromotion.setCreatedBy("system");
                    itemPromotion.setCreatedTime(Calendar.getInstance().getTime());
                    itemPromotion.setModifiedBy("system");
                    itemPromotion.setModifiedTime(Calendar.getInstance().getTime());
                    list.add(itemPromotion);
                }
            }
            catch (Exception ex){
                ex.printStackTrace();
            }
        }
        return  list;
    }

    private List<SaleOrderItem> getOrderItemList(String sale_no) {
        SaleOrderItemCriteria saleOrderItemCriteria = new SaleOrderItemCriteria();
        saleOrderItemCriteria.createCriteria().andSoNoEqualTo(sale_no);
        return saleOrderItemLogic.list(saleOrderItemCriteria);
    }
    //endregion

    //region 自动取消超时未支付订单
    public String autoCancel() {
        String rtn = "";
        logger.error("in method autoCancel");

        cancelLock.lock();

        try {
            //get cancel order start time
            Calendar start = Calendar.getInstance();
            start.add(Calendar.MINUTE, -orderCancelTimeout);
            //get orders
            SaleOrderCriteria saleOrderCriteria = new SaleOrderCriteria();
            saleOrderCriteria.createCriteria().andOrderTimeLessThan(start.getTime()).andPayTypeNotEqualTo(COD_NAME).andPayStatusEqualTo(SaleOrderPayStatus.WaitPay.value()).andStatusEqualTo(SaleOrderStatus.Created.value()).andIsDeleteEqualTo(0);
            saleOrderCriteria.or().andOrderTimeLessThan(start.getTime()).andPayTypeNotEqualTo(COD_NAME).andPayStatusEqualTo(SaleOrderPayStatus.PartialPay.value()).andStatusEqualTo(SaleOrderStatus.Created.value()).andIsDeleteEqualTo(0);

            List<SaleOrder> saleOrderList = saleOrderLogic.list(saleOrderCriteria);
            if (saleOrderList == null || saleOrderList.size() == 0) return rtn;
            //foreach cancel
            for (SaleOrder saleOrder : saleOrderList) {
                try {
                    orderService.internalCancel(saleOrder.getSaleNo(), "system", "");
                } catch (Exception e) {
                    logger.error("cacel order error.sale order  no :".concat(saleOrder.getSaleNo()));
                    logger.error(e.toString(), e);
                }
            }
        } finally {
            cancelLock.unlock();
        }
        return rtn;
    }
    //endregion
}
